#ifndef COMPILERGCC_H
#define COMPILERGCC_H

#include <wx/choice.h>
#include <wx/dynarray.h>
#include <wx/process.h>
#include <wx/timer.h>
#include <queue>
#include <M_Code_plugin.h>
#include <M_Code_project.h>
#include <compileoptionsbase.h>
#include <compilerfactory.h>
#include <logger.h>
#include <sdk_events.h>
#include "compilermessages.h"
#include "compilererrors.h"
#include "compiler_defs.h"

enum CompilerOptionsType {
  cotGlobal = 0,
  cotProjectOrTarget
};

enum ErrorType {
  etNone = 0,
  etError,
  etWarning
};


enum BuildJob {
  bjIdle = 0,
  bjWorkspace,
  bjProject,
  bjTarget
};


enum BuildState {
  bsNone = 0,
  bsProjectPreBuild,
  bsTargetClean,
  bsTargetPreBuild,
  bsTargetBuild,
  bsTargetPostBuild,
  bsTargetDone,
  bsProjectPostBuild,
  bsProjectDone
};

enum LogTarget {
  ltMessages = 0x01,
  ltFile = 0x02,
  ltAll = 0xff
};

enum BuildAction {
  baClean = 0,
  baBuild,
  baRun,
  baBuildFile
};

class wxComboBox;
class wxGauge;
class wxStaticText;
class BuildLogger;
class PipedProcess;

class CompilerGCC : public cbCompilerPlugin {
  public:
    CompilerGCC();
    virtual ~CompilerGCC();
    virtual void OnAttach();
    virtual void OnRelease( bool appShutDown );
    virtual void BuildModuleMenu( const ModuleType type, wxMenu* menu, const FileTreeData* data = 0 );
    virtual bool BuildToolBar( wxToolBar* toolBar );
    virtual int GetToolBarPriority() { return 1; }
    virtual int Run( ProjectBuildTarget* target = 0L );
    virtual int Run( const wxString& target );
    virtual int RunSingleFile( const wxString& filename );
    virtual int Clean( const wxString& target );
    virtual int Clean( ProjectBuildTarget* target = 0L );
    virtual int DistClean( ProjectBuildTarget* target = 0L );
    virtual int DistClean( const wxString& target );
    virtual int Build( ProjectBuildTarget* target = 0L );
    virtual int Build( const wxString& target );
    virtual int Rebuild( ProjectBuildTarget* target = 0L );
    virtual int Rebuild( const wxString& target );
    virtual int CleanWorkspace( const wxString& target = wxEmptyString );
    virtual int BuildWorkspace( const wxString& target = wxEmptyString );
    virtual int RebuildWorkspace( const wxString& target = wxEmptyString );
    virtual int CompileFile( const wxString& file );
    virtual int CompileFileWithoutProject( const wxString& file );
    virtual int CompileFileDefault( M_Code_Project* project, ProjectFile* pf, ProjectBuildTarget* bt );
    virtual int KillProcess();
    virtual bool IsRunning() const;
    virtual int GetExitCode() const { return m_LastExitCode; }
    virtual int Configure( M_Code_Project* project, ProjectBuildTarget* target = 0L );
    int GetConfigurationPriority() const { return 0; }
    int GetConfigurationGroup() const { return cgCompiler; }
    cbConfigurationPanel* GetConfigurationPanel( wxWindow* parent );
    bool IsValidTarget( const wxString& target ) const;
    void SwitchCompiler( const wxString& id );
    const wxString& GetCurrentCompilerID();
    void OnIdle( wxIdleEvent& event );
    void OnTimer( wxTimerEvent& event );
    void OnCompile( wxCommandEvent& event );
    void OnCompileFile( wxCommandEvent& event );
    void OnCleanFile( wxCommandEvent& event );
    void OnRebuild( wxCommandEvent& event );
    void OnCompileAll( wxCommandEvent& event );
    void OnRebuildAll( wxCommandEvent& event );
    void OnCleanAll( wxCommandEvent& event );
    void OnClean( wxCommandEvent& event );
    void OnRun( wxCommandEvent& event );
    void OnProjectCompilerOptions( wxCommandEvent& event );
    void OnTargetCompilerOptions( wxCommandEvent& event );
    void OnCompileAndRun( wxCommandEvent& event );
    void OnKillProcess( wxCommandEvent& event );
    void OnSelectTarget( wxCommandEvent& event );
    void OnNextError( wxCommandEvent& event );
    void OnPreviousError( wxCommandEvent& event );
    void OnClearErrors( wxCommandEvent& event );
    void OnUpdateUI( wxUpdateUIEvent& event );
    void OnConfig( wxCommandEvent& event );
  private:
    friend class CompilerOptionsDlg;
    void Dispatcher( wxCommandEvent& event );
    void TextURL( wxTextUrlEvent& event );
    bool StopRunningDebugger();
    bool ReAllocProcesses();
    void AllocProcesses();
    void FreeProcesses();
    bool IsProcessRunning( int idx = -1 ) const;
    int GetNextAvailableProcessIndex() const;
    int GetActiveProcessCount() const;
    void SetupEnvironment();
    void OnProjectActivated( CodeBlocksEvent& event );
    void OnProjectLoaded( CodeBlocksEvent& event );
    void OnProjectUnloaded( CodeBlocksEvent& event );
    void OnCompileFileRequest( CodeBlocksEvent& event );
    void OnGCCOutput( CodeBlocksEvent& event );
    void OnGCCError( CodeBlocksEvent& event );
    void OnGCCTerminated( CodeBlocksEvent& event );
    void OnJobEnd( size_t procIndex, int exitCode );
    void SaveOptions();
    void LoadOptions();
    void DoRegisterCompilers();
    void DoPrepareQueue( bool clearLog );
    void NotifyCleanProject( const wxString& target );
    void NotifyCleanWorkspace();
    int DoRunQueue();
    void DoClearTargetMenu();
    void DoRecreateTargetMenu();
    void DoUpdateTargetMenu( int targetIndex );
    FileTreeData* DoSwitchProjectTemporarily();
    ProjectBuildTarget* DoAskForTarget();
    int DoGUIAskForTarget();
    void ClearLog();
    void PrepareCompileFile( wxFileName& file );
    void PrepareCompileFilePM( wxFileName& file );
    bool CheckProject();
    void AskForActiveProject();
    void StartCompileFile( wxFileName file );
    void DoGotoNextError();
    void DoGotoPreviousError();
    void DoClearErrors();
    wxString ProjectMakefile();
    void AddOutputLine( const wxString& output, bool forceErrorColour = false );
    void LogWarningOrError( CompilerLineType lt, M_Code_Project* prj, const wxString& filename, const wxString& line, const wxString& msg );
    void LogMessage( const wxString& message, CompilerLineType lt = cltNormal, LogTarget log = ltAll, bool forceErrorColour = false, bool isTitle = false, bool updateProgress = false );
    void SaveBuildLog();
    void InitBuildLog( bool workspaceBuild );
    void PrintBanner( BuildAction action, M_Code_Project* prj = 0, ProjectBuildTarget* target = 0 );
    bool UseMake( M_Code_Project* project = 0 );
    struct CompilerValidResult {
      Compiler *compiler = nullptr;
      bool isValid = false;
    };
    CompilerValidResult CompilerValid( ProjectBuildTarget* target = 0 );
    void PrintInvalidCompiler( ProjectBuildTarget *target, Compiler *compiler, const wxString &finalMessage );
    ProjectBuildTarget* GetBuildTargetForFile( ProjectFile* pf );
    wxString GetMakeCommandFor( MakeCommand cmd, M_Code_Project* project, ProjectBuildTarget* target );
    int DoBuild( bool clean, bool build );
    int DoBuild( const wxString& target, bool clean, bool build, bool clearLog = true );
    int DoWorkspaceBuild( const wxString& target, bool clean, bool build, bool clearLog = true );
    void CalculateWorkspaceDependencies( wxArrayInt& deps );
    void CalculateProjectDependencies( M_Code_Project* prj, wxArrayInt& deps );
    void InitBuildState( BuildJob job, const wxString& target );
    void ResetBuildState();
    void BuildStateManagement();
    BuildState GetNextStateBasedOnJob();
    void NotifyJobDone( bool showNothingToBeDone = false );
    void AddToCommandQueue( const wxArrayString& commands );
    int GetTargetIndexFromName( M_Code_Project* prj, const wxString& name );
    void UpdateProjectTargets( M_Code_Project* project );
    wxString GetTargetString( int index = -1 );
    void DoClean( const wxArrayString& commands );
    bool DoCleanWithMake( ProjectBuildTarget* bt );
    wxString GetCurrentCompilerID( ProjectBuildTarget* target );
    wxString GetErrWarnStr();
    wxString GetMinSecStr();
    struct BuildJobTarget {
      BuildJobTarget( M_Code_Project* p = 0, const wxString& n = wxEmptyString ) : project( p ), targetName( n ) {}
      M_Code_Project* project;
      wxString targetName;
    };
    typedef std::queue<BuildJobTarget> BuildJobTargetsList;
    BuildJobTargetsList m_BuildJobTargetsList;
    void ExpandTargets( M_Code_Project* project, const wxString& targetName, wxArrayString& result );
    void PreprocessJob( M_Code_Project* project, const wxString& targetName );
    BuildJobTarget GetNextJob();
    const BuildJobTarget& PeekNextJob();
    struct CompilerProcess {
      PipedProcess* pProcess;
      wxString OutputFile;
      long int PID;
    };
    typedef std::vector<CompilerProcess> CompilerProcessList;
    CompilerProcessList m_CompilerProcessList;
    wxArrayString m_Targets;
    int m_RealTargetsStartIndex;
    int m_RealTargetIndex;
    CompilerQueue m_CommandQueue;
    wxString m_CompilerId;
    int m_PageIndex;
    int m_ListPageIndex;
    wxMenu* m_Menu;
    wxMenu* m_TargetMenu;
    int m_TargetIndex;
    wxMenu* m_pErrorsMenu;
    M_Code_Project* m_pProject;
    wxToolBar* m_pTbar;
    wxTimer m_timerIdleWakeUp;
    BuildLogger* m_pLog;
    CompilerMessages* m_pListLog;
    wxChoice* m_pToolTarget;
    bool m_RunAfterCompile;
    wxString m_CdRun;
    wxString m_RunCmd;
    int m_LastExitCode,xml_File_lock;
    CompilerErrors m_Errors;
    wxString m_LastTargetName;
    bool m_NotifiedMaxErrors;
    wxLongLong m_StartTime;
    M_Code_Project* m_pBuildingProject;
    wxString m_BuildingTargetName;
    BuildJob m_BuildJob;
    BuildState m_BuildState;
    BuildState m_NextBuildState;
    M_Code_Project* m_pLastBuildingProject;
    ProjectBuildTarget* m_pLastBuildingTarget;
    bool m_Clean;
    bool m_Build;
    bool m_LastBuildStep;
    bool m_RunTargetPostBuild;
    bool m_RunProjectPostBuild;
    bool m_IsWorkspaceOperation;
    wxString   m_BuildLogFilename;
    wxString   m_BuildLogTitle;
    wxString   m_BuildLogContents;
    wxDateTime m_BuildStartTime;
    size_t m_MaxProgress;
    size_t m_CurrentProgress;
    DECLARE_EVENT_TABLE()
};

#endif
